package com.yun.partnerSys.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yun.partnerSys.model.dto.TeamQuery;
import com.yun.partnerSys.common.ErrorCode;
import com.yun.partnerSys.exception.BusinessException;
import com.yun.partnerSys.mapper.TeamMapper;
import com.yun.partnerSys.model.domain.Team;
import com.yun.partnerSys.model.domain.User;
import com.yun.partnerSys.model.domain.UserTeam;
import com.yun.partnerSys.model.enums.TeamStatusEnum;
import com.yun.partnerSys.model.request.TeamJoinRequest;
import com.yun.partnerSys.model.request.TeamQuitRequest;
import com.yun.partnerSys.model.request.TeamUpdateRequest;
import com.yun.partnerSys.model.vo.TeamUserVO;
import com.yun.partnerSys.model.vo.UserVO;
import com.yun.partnerSys.service.TeamService;
import com.yun.partnerSys.service.UserService;
import com.yun.partnerSys.service.UserTeamService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 队伍服务实现类
 *
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserService userService;

    @Resource
    private RedissonClient redissonClient;

    @Override
    @Transactional
    public long addTeam(Team team, User loginUser) {
//        请求参数是否为空？
        if(team == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
//        是否登录，未登录不允许创建
        if(loginUser == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
//        校验信息
//        队伍人数 > 1 且 <= 20
        Integer maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if(maxNum<1||maxNum>20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数不满足要求");
        }
//        队伍标题 <= 20
        String name = team.getName();
        if(StringUtils.isBlank(name)||name.length()>20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍标题不满足要求");
        }
//        描述 <= 512
        String description = team.getDescription();
        if(StringUtils.isNotBlank(description) && description.length()>512){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍描述太长");
        }
//        status 是否公开（int）不传默认为 0（公开）
        Integer status = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if(statusEnum == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍状态不满足要求");
        }
//        如果 status 是加密状态，一定要有密码，且密码 <= 32
        String password = team.getPassword();
        if(TeamStatusEnum.SECRET.equals(statusEnum)){
            if(StringUtils.isBlank(password) || password.length()>32){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码设置错误");
            }
        }
//        超时时间 > 当前时间
        Date expireTime = team.getExpireTime();
        if(new Date().after(expireTime)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"超时时间 > 当前时间");
        }
//        校验用户最多创建 5 个队伍
        // todo 有 bug，可能同时创建 100 个队伍
        long userId = loginUser.getId().longValue();
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",userId);
        long hasTeamNum = this.count(queryWrapper);
        if(hasTeamNum>=5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户最多创建5个队伍");
        }
//        插入队伍信息到队伍表
        team.setId(null);
        team.setUserId(userId);
        boolean result = this.save(team);
        Long teamId = team.getId();

        if(!result || teamId == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"创建队伍失败");
        }
//        插入用户 => 队伍关系到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setTeamId(team.getId());
        userTeam.setUserId(userId);
        userTeam.setJoinTime(new Date());
        result = userTeamService.save(userTeam);

        if(!result){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"创建队伍失败");
        }

        return teamId;
    }

    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery, boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        if (teamQuery != null) {
            Long id = teamQuery.getId();
            if (id != null && id > 0) {
                queryWrapper.eq("id", id);
            }
            // todo 关联查询已加入的其他用户信息
            List<Long> idList = teamQuery.getIdList();
            if (!CollectionUtils.isEmpty(idList)) {
                queryWrapper.in("id", idList);
            }
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
            }
            String name = teamQuery.getName();
            if (StringUtils.isNotBlank(name)) {
                queryWrapper.like("name", name);
            }
            String description = teamQuery.getDescription();
            if (StringUtils.isNotBlank(description)) {
                queryWrapper.like("description", description);
            }
            Integer maxNum = teamQuery.getMaxNum();
            // 查询最大人数相等的
            if (maxNum != null && maxNum > 0) {
                queryWrapper.eq("maxNum", maxNum);
            }
            Long userId = teamQuery.getUserId();
            // 根据创建人来查询
            if (userId != null && userId > 0) {
                queryWrapper.eq("userId", userId);
            }
            // 根据状态来查询
            Integer status = teamQuery.getStatus();
            TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
            if (statusEnum == null) {
                statusEnum = TeamStatusEnum.PUBLIC;
            }
            if (!isAdmin && statusEnum.equals(TeamStatusEnum.PRIVATE)) {
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            queryWrapper.eq("status", statusEnum.getValue());
        }
        // 不展示已过期的队伍
        queryWrapper.and(qw -> qw.gt("expireTime",new Date()).or().isNull("expireTime"));
        List<Team> teamList = this.list(queryWrapper);

        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        // 关联查询创建人的用户信息
        for(Team team:teamList){
            Long userId = team.getUserId();
            if(userId==null){
                continue;
            }
            User user = userService.getById(userId);
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team,teamUserVO);
            //用户脱敏
            if(user != null){
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user,userVO);
                teamUserVO.setCreateUser(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }
        return teamUserVOList;
    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        if(teamUpdateRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateRequest.getId();
        if(id == null || id<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team oldTeam = this.getById(id);
        if(oldTeam == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"该队伍不存在");
        }

        //只有管理员和用户自己能修改队伍
        if(!oldTeam.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NO_AUTH);
        }

        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(teamUpdateRequest.getStatus());
        if(statusEnum.equals(TeamStatusEnum.SECRET)){
            if(teamUpdateRequest.getPassword()==null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"设置私密队伍必须设置密码");
            }
        }
        Team team = new Team();
        BeanUtils.copyProperties(teamUpdateRequest,team);
        return this.updateById(team);
    }

    //todo 加分布式锁
    @Override
    public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
        if(teamJoinRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //不能参加已过期的队伍
        Long teamId = teamJoinRequest.getTeamId();
        Team team = getTeamById(teamId);
        Date expireTime = team.getExpireTime();
        if(expireTime != null && expireTime.before(new Date())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不允许加入已过期的队伍");
        }

        //不能加入私密队伍
        Integer status = team.getStatus();
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if(TeamStatusEnum.PRIVATE.equals(statusEnum)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能加入私密队伍");
        }

        //加入加密队伍需要密码
        String password = teamJoinRequest.getPassword();
        if(TeamStatusEnum.SECRET.equals(statusEnum)){
            if(StringUtils.isBlank(password) || !password.equals(team.getPassword()))
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码错误");
        }

        //最多创建和参加5个队伍
        long userId = loginUser.getId().longValue();

        // todo 需要完善，实现不影响不同用户加入团队
        RLock lock = redissonClient.getLock("yupao:join_team");
        try {
            while(true){
                if(lock.tryLock(0,-1, TimeUnit.SECONDS)){
                    System.out.println("getLock"+Thread.currentThread().getId());
                    QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId",userId);
                    long hasJoinNum = userTeamService.count(queryWrapper);
                    if(hasJoinNum >= 5){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"最多创建和参加5个队伍");
                    }

                    //不能重复加入队伍
                    queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId",userId);
                    queryWrapper.eq("teamId",teamId);
                    long hasJoin = userTeamService.count(queryWrapper);
                    if(hasJoin > 0){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能重复加入队伍");
                    }

                    //不能加入已满队伍
                    long teamHasNum = countTeamUserByTeamId(teamId);
                    if(teamHasNum >= team.getMaxNum()){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数已满");
                    }

                    //更新队伍信息
                    UserTeam userTeam = new UserTeam();
                    userTeam.setTeamId(teamId);
                    userTeam.setUserId(userId);
                    userTeam.setJoinTime(new Date());
                    boolean success = userTeamService.save(userTeam);

                    return success;
                }
            }
        }catch (Exception e){
           // log.error("",e);
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能重复加入队伍");
            //return false;
        }finally {
            //判断是否为自己线程的锁
            if(lock.isHeldByCurrentThread()){
                System.out.println("unLock"+Thread.currentThread().getId());
                lock.unlock();
            }
        }

    }

    @Override
    @Transactional
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {

        if(teamQuitRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamQuitRequest.getTeamId();
        Team team = getTeamById(teamId);

        //判断是否加入过队伍
        Long userId = loginUser.getId();
        UserTeam queryUserTeam = new UserTeam();
        queryUserTeam.setUserId(userId);
        queryUserTeam.setTeamId(teamId);
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(queryUserTeam);
        long count = userTeamService.count(queryWrapper);
        if(count == 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"未加入队伍");
        }

        long teamHasJoinNum = countTeamUserByTeamId(teamId);

        if(teamHasJoinNum == 1){
            // 队伍只剩一人，解散
            this.removeById(teamId);
        }else{
            //队伍还剩至少两人
            //如果是队长退出
            if(userId.equals(team.getUserId())){
                //把队伍交给最早加入的用户
                //查询队伍最早加入的2个人
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId",teamId);
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if(CollectionUtils.isEmpty(userTeamList) || userTeamList.size() < 1){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Long newTeamLeaderId = nextUserTeam.getUserId();
                //更新队伍队长
                Team updateTeam = new Team();
                updateTeam.setUserId(newTeamLeaderId);
                updateTeam.setId(teamId);
                boolean result = this.updateById(updateTeam);
                if(!result){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR,"更新队伍信息失败");
                }
            }
        }
        return userTeamService.remove(queryWrapper);
    }



    @Override
    @Transactional
    public boolean deleteTeam(long id, User loginUser) {
        // 校验队伍是否存在
        Team team = getTeamById(id);

        // 校验用户是否为队长
        if(!loginUser.getId().equals(team.getUserId())){
            throw new BusinessException(ErrorCode.NO_AUTH,"无权限");
        }
        // 移除所有队伍关联信息
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        Long teamId = team.getId();
        queryWrapper.eq("teamId", teamId);
        boolean result = userTeamService.remove(queryWrapper);
        if(!result){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"移除队伍关联信息失败");
        }
        // 移除队伍
        return this.removeById(teamId);
    }


    /*
     * 根据Id获取队伍信息
     *
     * */
    private Team getTeamById(Long teamId) {
        if(teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = getById(teamId);
        if(team == null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        return team;
    }

    /*
    *  计算某队伍已加入人数
    *
    * */
    private long countTeamUserByTeamId(Long teamId) {
        QueryWrapper<UserTeam> queryWrapper;
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId);
        long teamHasNum = userTeamService.count(queryWrapper);
        return teamHasNum;
    }
}




